package com.ruoyi.common.utils.digest;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

/**
 * 信息摘要算法工具类
 *
 * @author 李志慧
 */
public class DigestUtil extends BouncyCastleBase {
    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private static final int STREAM_BUFFER_LENGTH = 1024;

    /**
     * 散列函数算法
     */
    public static final String DIGEST_MD2 = "MD2";
    public static final String DIGEST_MD4 = "MD4";
    public static final String DIGEST_MD5 = "MD5";
    public static final String DIGEST_SHA_1 = "SHA-1";
    public static final String DIGEST_SHA_224 = "SHA-224";
    public static final String DIGEST_SHA_256 = "SHA-256";
    public static final String DIGEST_SHA_384 = "SHA-384";
    public static final String DIGEST_SHA_512 = "SHA-512";
    public static final String DIGEST_SHA3_224 = "SHA3-224";
    public static final String DIGEST_SHA3_256 = "SHA3-256";
    public static final String DIGEST_SHA3_384 = "SHA3-384";
    public static final String DIGEST_SHA3_512 = "SHA3-512";
    public static final String DIGEST_SM3 = "SM3";

    /**
     * 含有密钥的散列函数算法
     */
    public static final String HmacMD5 = "HmacMD5";
    public static final String HmacMD2 = "HmacMD2";
    public static final String HmacMD4 = "HmacMD4";
    public static final String HmacSHA1 = "HmacSHA1";
    public static final String HmacSHA256 = "HmacSHA256";
    public static final String HmacSHA384 = "HmacSHA384";
    public static final String HmacSHA512 = "HmacSHA512";

    /**
     * 获取信息摘要算法
     *
     * @param algorithm 算法
     * @return MessageDigest
     */
    public static MessageDigest getDigest(final String algorithm) {
        try {
            return MessageDigest.getInstance(algorithm, "BC");
        } catch (Exception e) {
            throw new SecurityException(e);
        }
    }

    /**
     * 根据指定的算法计算消息摘要
     *
     * @param algorithm 算法
     * @param data      数据
     * @return ByteSource
     */
    public static ByteSource degist(String algorithm, String data) {
        MessageDigest messageDigest = getDigest(algorithm);
        byte[] bytes;
        if (data != null) {
            bytes = data.getBytes(DEFAULT_CHARSET);
        } else {
            return new ByteSource();
        }
        messageDigest.update(bytes);
        return new ByteSource(messageDigest.digest());
    }

    /**
     * 根据指定的算法计算消息摘要
     *
     * @param algorithm 算法
     * @param data      数据
     * @return ByteSource
     */
    public static ByteSource degist(String algorithm, InputStream data) {
        try {
            MessageDigest messageDigest = getDigest(algorithm);
            final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
            int len = data.read(buffer);
            while (len > -1) {
                messageDigest.update(buffer, 0, len);
                len = data.read(buffer);
            }
            return new ByteSource(messageDigest.digest());
        } catch (Exception e) {
            throw new SecurityException(e);
        }
    }

    public static ByteSource md2(String data) {
        return degist(DIGEST_MD2, data);
    }

    public static ByteSource md2(InputStream data) {
        return degist(DIGEST_MD2, data);
    }

    public static ByteSource md4(String data) {
        return degist(DIGEST_MD4, data);
    }

    public static ByteSource md4(InputStream data) {
        return degist(DIGEST_MD4, data);
    }

    public static ByteSource md5(String data) {
        return degist(DIGEST_MD5, data);
    }

    public static ByteSource md5(InputStream data) {
        return degist(DIGEST_MD5, data);
    }

    public static ByteSource sha1(String data) {
        return degist(DIGEST_SHA_1, data);
    }

    public static ByteSource sha1(InputStream data) {
        return degist(DIGEST_SHA_1, data);
    }

    public static ByteSource sha224(String data) {
        return degist(DIGEST_SHA_224, data);
    }

    public static ByteSource sha224(InputStream data) {
        return degist(DIGEST_SHA_224, data);
    }

    public static ByteSource sha256(String data) {
        return degist(DIGEST_SHA_256, data);
    }

    public static ByteSource sha256(InputStream data) {
        return degist(DIGEST_SHA_256, data);
    }

    public static ByteSource sha384(String data) {
        return degist(DIGEST_SHA_384, data);
    }

    public static ByteSource sha384(InputStream data) {
        return degist(DIGEST_SHA_384, data);
    }

    public static ByteSource sha512(String data) {
        return degist(DIGEST_SHA_512, data);
    }

    public static ByteSource sha512(InputStream data) {
        return degist(DIGEST_SHA_512, data);
    }

    public static ByteSource sm3(String data) {
        return degist(DIGEST_SM3, data);
    }

    public static ByteSource sm3(InputStream data) {
        return degist(DIGEST_SM3, data);
    }

    public static ByteSource sha3_224(String data) {
        return degist(DIGEST_SHA3_224, data);
    }

    public static ByteSource sha3_224(InputStream data) {
        return degist(DIGEST_SHA3_224, data);
    }

    public static ByteSource sha3_256(String data) {
        return degist(DIGEST_SHA3_256, data);
    }

    public static ByteSource sha3_256(InputStream data) {
        return degist(DIGEST_SHA3_256, data);
    }

    public static ByteSource sha3_384(String data) {
        return degist(DIGEST_SHA3_384, data);
    }

    public static ByteSource sha3_384(InputStream data) {
        return degist(DIGEST_SHA3_384, data);
    }

    public static ByteSource sha3_512(String data) {
        return degist(DIGEST_SHA3_512, data);
    }

    public static ByteSource sha3_512(InputStream data) {
        return degist(DIGEST_SHA3_512, data);
    }

    /**
     * 生成消息认证码算法密码
     *
     * @param algorithm 算法
     * @return
     */
    public static ByteSource generateHmacKey(String algorithm) {
        try {
            //初始化KeyGenerator
            KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm, "BC");
            //产生密钥
            SecretKey secretKey = keyGenerator.generateKey();
            //获取密钥
            return new ByteSource(secretKey.getEncoded());
        } catch (Exception e) {
            throw new SecurityException(e);
        }
    }

    /**
     * 根据指定的算法计算消息摘要
     *
     * @param algorithm 算法
     * @param key       密码
     * @param data      数据
     * @return ByteSource
     */
    public static ByteSource hmacDegist(String algorithm, byte[] key, String data) {
        try {
            if (data == null) {
                return new ByteSource();
            }
            //还原密钥，因为密钥是以byte形式为消息传递算法所拥有
            SecretKey secretKey = new SecretKeySpec(key, algorithm);
            //实例化Mac
            Mac mac = Mac.getInstance(secretKey.getAlgorithm(), "BC");
            //初始化Mac
            mac.init(secretKey);
            //执行消息摘要处理
            byte[] result = mac.doFinal(data.getBytes(DEFAULT_CHARSET));
            return new ByteSource(result);
        } catch (Exception e) {
            throw new SecurityException(e);
        }
    }


}
